#!/usr/bin/env bash
# Copyright (c) 2017 Presto Labs Pte. Ltd.
# Author: leon

# Usage:
# ./deploy.sh <specific target directory>

set -e

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
REPO_ROOT="$(git rev-parse --show-toplevel)"
cd ${REPO_ROOT}

SPECIFIC_TARGET_DIR="${1}"
if [ ! -d ${SPECIFIC_TARGET_DIR} ]; then
  echo "Not a valid target directory!"
fi

echo -e "\e[1;97m[Configuration]\e[0m"
${SCRIPT_DIR}/print_config.sh ${SPECIFIC_TARGET_DIR}/config

# Gets configuration parameters.
source ${SPECIFIC_TARGET_DIR}/config

TIMETAG=$(TZ="${TZ}" date "+%Y%m%d-%H%M%S%z")
DEPLOY_NAME="${PACKAGE_NAME}_${TIMETAG}"

LOCAL_DEPLOY_BASE="${HOME}/deploy"
LOCAL_DEPLOY_DIR="${LOCAL_DEPLOY_BASE}/${DEPLOY_NAME}"

DEPLOY_EXTRA_INFO_STDOUT="/dev/null"
DEPLOY_EXTRA_INFO_STDERR="/dev/null"
if [ "${VERBOSE}" == "yes" ]  || \
   [ "${VERBOSE}" == "y" ]    || \
   [ "${VERBOSE}" == "true" ]
then
  DEPLOY_EXTRA_INFO_STDOUT="/dev/stdout"
  DEPLOY_EXTRA_INFO_STDERR="/dev/stderr"
fi

if [ "${BAKE_DEPLOY_WITH_LOCAL_CHANGES}" == "true" ]; then
  echo "dirty, but goes on"
else
  if [ "$(git status --porcelain)" ]; then
    echo "dirty"
    exit 1
  fi
fi

echo -e "\e[1;97m[Creating LOCAL_DEPLOY_DIR]\e[0m"
echo -e "${LOCAL_DEPLOY_DIR}"
mkdir -p "${LOCAL_DEPLOY_DIR}"

echo -e "\e[1;97m[Baking C++ binaries]\e[0m"
bazel clean > "${DEPLOY_EXTRA_INFO_STDOUT}"

function convert_bake_binary_bazel_target() {
  # replace bin_opt/ or bin/ with //
  # replace last / with :
  echo $1 | sed 's|bin/|//|' | sed 's|bin_opt/|//|' | rev | sed 's|/|:|' | rev
}
function convert_bazel_binary_bazel_target() {
  # replace bazel-bin/ with //
  # replace last / with :
  echo $1 | sed 's|bazel-bin/|//|' | rev | sed 's|/|:|' | rev
}
function convert_bazel_target_bazel_binary() {
  # replace // with bazel-bin/
  # replace last : with /
  # or use bazel aquery
  echo $1 | sed 's|//|bazel-bin/|' | rev | sed 's|:|/|' | rev
}

for input_binary in ${BAKE_BINARY[@]}; do
  if [ -z "${input_binary}" ]; then
    continue
  fi
  echo "  Building ${input_binary} ..."
  if [[ ${input_binary} =~ ^bin_opt/.* ]]; then
      BAZEL_FLAGS="--config=opt"
      LAUNCH_BIN_DIR="bin_opt"
      target=$(convert_bake_binary_bazel_target $input_binary)
  elif [[ ${input_binary} =~ ^bin/.* ]]; then
      BAZEL_FLAGS="--config=dbg"
      LAUNCH_BIN_DIR="bin"
      target=$(convert_bake_binary_bazel_target $input_binary)
  else
      BAZEL_FLAGS="--config=opt"
      LAUNCH_BIN_DIR="bin_opt"
      target=$(convert_bazel_binary_bazel_target $input_binary)
  fi
  binary=$(convert_bazel_target_bazel_binary $target)

  if [ -n "${BAZEL_BUILD_OPTION}" ]; then
    BAZEL_FLAGS="${BAZEL_FLAGS} ${BAZEL_BUILD_OPTION}"
  fi

  echo "    input_binary", ${input_binary}
  echo "    target", ${target}
  echo "    binary", ${binary}
  echo "    bazel_flags", ${BAZEL_FLAGS}

  (trap "echo 'simple_deployer Failed @ bazel'" ERR
    cd "${REPO_ROOT}"
    bazel build ${BAZEL_FLAGS}\
      "${target}" > "${DEPLOY_EXTRA_INFO_STDOUT}"
    rsync -arv -L ${binary}.runfiles/coin/ $LOCAL_DEPLOY_DIR/
    cd "${LOCAL_DEPLOY_DIR}"
    ln -sfn "./" "${LAUNCH_BIN_DIR}"
  trap - ERR)
done

# Copy data files.
echo -e "\e[1;97m[Copying data file]\e[0m"
for _data in ${DATA_FILE[@]}; do
  if [ -z "${_data}" ]; then
    continue
  fi
  echo "  Copying ${_data} ..."
  cp -r --parents "${_data}" "${LOCAL_DEPLOY_DIR}/"
done

# Runs post-build actions.
echo -e "\e[1;97m[Running post-build actions]\e[0m"
mkdir -p "${LOCAL_DEPLOY_DIR}/deploy"
cp -r ${SCRIPT_DIR}/scripts_for_target_machine/* "${LOCAL_DEPLOY_DIR}/deploy/"
if [ -d "${SPECIFIC_TARGET_DIR}/files" ]; then
  cp -r ${SPECIFIC_TARGET_DIR}/files/* "${LOCAL_DEPLOY_DIR}/"
fi
if [ -f "${SPECIFIC_TARGET_DIR}/cron_profile" ]; then
  cp "${SPECIFIC_TARGET_DIR}/cron_profile" "${LOCAL_DEPLOY_DIR}/deploy/"
  sed -i -- 's/\$DEPLOY_NAME/'"${DEPLOY_NAME}"'/g' "${LOCAL_DEPLOY_DIR}/deploy/cron_profile"
fi
echo "PACKAGE_NAME=\"${PACKAGE_NAME}\"" >> "${LOCAL_DEPLOY_DIR}/deploy/profile"
echo "DEPLOY_NAME=\"${DEPLOY_NAME}\"" >> "${LOCAL_DEPLOY_DIR}/deploy/profile"
echo "RECENT_DIR=\"${REMOTE_MACHINE_RECENT_DIR}\"" >> "${LOCAL_DEPLOY_DIR}/deploy/profile"
if [ -n "${RETENTION}" ]; then
  echo "RETENTION=${RETENTION}" >> "${LOCAL_DEPLOY_DIR}/deploy/profile"
fi

# Logs repositories' status.
LOCAL_DEPLOY_REVISION="${LOCAL_DEPLOY_DIR}/deploy/revision"
echo "== git log ==" > "${LOCAL_DEPLOY_REVISION}"
git log -n 1 >> "${LOCAL_DEPLOY_REVISION}"
echo >> "${LOCAL_DEPLOY_REVISION}"
echo "== git status ==" >> "${LOCAL_DEPLOY_REVISION}"
git status >> "${LOCAL_DEPLOY_REVISION}"

# Logs extra debugging information
mkdir -p "${LOCAL_DEPLOY_DIR}/deploy/log"
printenv &> "${LOCAL_DEPLOY_DIR}/deploy/log/deploy_env"
domainname -f &> "${LOCAL_DEPLOY_DIR}/deploy/log/deploy_host"
uname -a &> "${LOCAL_DEPLOY_DIR}/deploy/log/deploy_uname"
date &> "${LOCAL_DEPLOY_DIR}/deploy/log/deploy_time"

# Archives package.
echo -e "\e[1;97m[Archiving]\e[0m"
cd "${LOCAL_DEPLOY_BASE}"
tar czf "${DEPLOY_NAME}.tgz" "${DEPLOY_NAME}"

# Deploys to remote machine
for _machine in ${REMOTE_MACHINE[@]}; do
  if [ -z "${_machine}" ]; then
    continue
  fi
  echo -e "\e[1;97m[Deploying to ${_machine}]\e[0m"
  echo "if [ ! -d ${REMOTE_MACHINE_DEPLOY_DIR} ]; then mkdir -p ${REMOTE_MACHINE_DEPLOY_DIR}; fi" | ssh "${REMOTE_MACHINE_USER}@${_machine}" "bash -s"
  scp -C "${DEPLOY_NAME}.tgz" "${REMOTE_MACHINE_USER}@${_machine}:${REMOTE_MACHINE_DEPLOY_DIR}/"
done

# Runs a bootstrap script.
for _machine in ${REMOTE_MACHINE[@]}; do
  if [ -z "${_machine}" ]; then
    continue
  fi
  echo -e "\e[1;97m[Bootstrapping at ${_machine}]\e[0m"
  echo "cd ${REMOTE_MACHINE_DEPLOY_DIR} && tar xzf ${DEPLOY_NAME}.tgz && rm -f ${DEPLOY_NAME}.tgz" | ssh "${REMOTE_MACHINE_USER}@${_machine}" "bash -s"
  ssh "${REMOTE_MACHINE_USER}@${_machine}" "${REMOTE_MACHINE_DEPLOY_DIR}/${DEPLOY_NAME}/deploy/bootstrap.sh"
done

echo -e "\e[1;92m[Done]\e[0m"
echo "- Package directory: ${LOCAL_DEPLOY_DIR}"
echo "- Package: ${LOCAL_DEPLOY_DIR}.tgz"
